package cn.jbolt.core.base.config;

import cn.hutool.setting.Setting;
import cn.jbolt.core.Interceptor.JBoltExceptionGlobalInterceptor;
import cn.jbolt.core.Interceptor.reqlimit.redis.JBoltRedisRateLimitUtil;
import cn.jbolt.core.actionreport.JBoltActionReport;
import cn.jbolt.core.actionreport.JBoltActionReportLogWriter;
import cn.jbolt.core.base.JBoltActionMapping;
import cn.jbolt.core.base.JBoltGlobalConfigKey;
import cn.jbolt.core.base.JBoltRequestType;
import cn.jbolt.core.bean.JBoltDateRange;
import cn.jbolt.core.cache.*;
import cn.jbolt.core.cache.caffeine.CaffeineCache;
import cn.jbolt.core.cache.redis.RedisCache;
import cn.jbolt.core.captcha.JBoltCaptchaCache;
import cn.jbolt.core.common.enums.JBoltUserOnlineState;
import cn.jbolt.core.converter.JBoltTimestampConverter;
import cn.jbolt.core.db.datasource.JBoltDataSourceUtil;
import cn.jbolt.core.db.datasource.JBoltDatasource;
import cn.jbolt.core.db.sql.DBType;
import cn.jbolt.core.db.sql.SqlUtil;
import cn.jbolt.core.db.util.JBoltTxKit;
import cn.jbolt.core.enjoy.directive.*;
import cn.jbolt.core.enumutil.JBoltEnum;
import cn.jbolt.core.enumutil.JBoltEnumBean;
import cn.jbolt.core.handler.base.*;
import cn.jbolt.core.json.JBoltFastJson;
import cn.jbolt.core.json.JBoltFastJsonFactory;
import cn.jbolt.core.kit.*;
import cn.jbolt.core.model.*;
import cn.jbolt.core.model.base.JBoltModelConfig;
import cn.jbolt.core.para.JBoltDateRangeParaGetter;
import cn.jbolt.core.para.JBoltPara;
import cn.jbolt.core.para.JBoltParaGetter;
import cn.jbolt.core.para.jbolttablemenufilter.JBoltTableMenuFilter;
import cn.jbolt.core.para.jbolttablemenufilter.JBoltTableMenuFilterGetter;
import cn.jbolt.core.permission.JBoltUserAuthKit;
import cn.jbolt.core.plugin.JBoltActiveRecordPlugin;
import cn.jbolt.core.render.JBoltRenderFactory;
import cn.jbolt.core.safe.XssHandler;
import cn.jbolt.core.sensitiveword.JBoltSensitiveWordUtil;
import cn.jbolt.core.service.JBoltProjectSystemLogProcessor;
import cn.jbolt.core.util.JBoltColorUtil;
import cn.jbolt.core.util.JBoltDateUtil;
import cn.jbolt.core.util.JBoltDesUtil;
import cn.jbolt.core.util.JBoltRandomUtil;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.jfinal.config.*;
import com.jfinal.core.ActionReporter;
import com.jfinal.core.converter.TypeConverter;
import com.jfinal.core.paragetter.ParaProcessorBuilder;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.generator.TableMeta;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.proxy.ProxyManager;
import com.jfinal.render.ViewType;
import com.jfinal.template.Engine;
import com.jfinal.template.source.ClassPathSourceFactory;

import java.sql.Timestamp;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * JBolt项目配置类 需要子类继承
 * @ClassName:  JBoltProjectConfig
 * @author: JFinal学院-小木 QQ：909854136
 * @date:   2022年2月13日
 */
public abstract class JBoltProjectConfig extends JFinalConfig {

	@Override
	public void configConstant(Constants me) {
		// 加载配置
		JBoltConfig.loadConfig();
		me.setDevMode(JBoltConfig.DEV_MODE);
		// 设置默认上传文件保存路径 getFile等使用
		me.setBaseUploadPath(JBoltConfig.prop.get("base_upload_path"));
		// 设置上传最大限制尺寸
		me.setMaxPostSize(1024 * JBoltConfig.prop.getInt("max_post_size",1024 * 20));
		// 支持 Controller、Interceptor、Validator 之中使用 @Inject 注入业务层，并且自动实现 AOP
		// 注入动作支持任意深度并自动处理循环注入
		me.setInjectDependency(true);
		// 可以直接访问JSP
		// me.setDenyAccessJsp(false);
		// 设置是否对超类进行注入
		me.setInjectSuperClass(true);
		// 设置默认下载文件路径 renderFile使用
		me.setBaseDownloadPath(JBoltConfig.prop.get("base_download_path", "download"));
		// 设置默认视图类型
		me.setViewType(ViewType.JFINAL_TEMPLATE);
		//初始化JBoltFastJson
		JBoltFastJson.init();
		// 设置json工厂
		me.setJsonFactory(JBoltFastJsonFactory.me());
		// 设置JBolt专用actionMapping 定制
		me.setActionMapping((routes)->new JBoltActionMapping(routes));
		//设置JBolt专用的renderFactory
		me.setRenderFactory(new JBoltRenderFactory());
		//如果开启了验证码放缓存
		if(JBoltConfig.CAPTCHA_CACHE_ENABLE){
			//设置验证码缓存
			me.setCaptchaCache(new JBoltCaptchaCache());
		}
		//设置proxy生成信息不输出的console和日志里
		ProxyManager.me().setPrintGeneratedClassToLog(false);
		ProxyManager.me().setPrintGeneratedClassToConsole(false);
		//判断是否使用cglib、Javassist
		if(JBoltConfig.isProxyByCglib()){
			me.setToCglibProxyFactory();
		}else if(JBoltConfig.isProxyByJavassist()){
			me.setToJavassistProxyFactory();
		}
		//是否开启java.awt.headless模式
		if(JBoltConfig.JAVA_AWT_HEADLESS_ENABLE){
			me.setToJavaAwtHeadless();
		}
		// 单独处理数据库内字段是datetime类型的时候 页面使用了Html5组件的时间选择组件 type="datetime-local"的
		TypeConverter.me().regist(Timestamp.class, new JBoltTimestampConverter());
		// JFinal设置使用Slf4j
		me.setToSlf4jLogFactory();
		// 判断action report输出方式是jboltlog的话 就使用JBolt的日志输出到控制台和文件归档
		if (JBoltConfig.ACTION_REPORT_WRITER.equals("jboltlog")) {
			// 设置actionReport输出
			ActionReporter.setWriter(new JBoltActionReportLogWriter());
		}
		//设置ActionReport自定义
		me.setActionReporter(new JBoltActionReport());
		// 参数获取器注册
		ParaProcessorBuilder.me.regist(JBoltPara.class, JBoltParaGetter.class, null);
		ParaProcessorBuilder.me.regist(JBoltDateRange.class, JBoltDateRangeParaGetter.class, null);
		// 参数JBoltTableMenuFilter获取器注册
		ParaProcessorBuilder.me.regist(JBoltTableMenuFilter.class, JBoltTableMenuFilterGetter.class, null);
		JBoltConfig.setProjectSystemLogProcessor(getProjectSystemLogProcessor());
		//设置是否解析 json 请求 action 参数解析json请求 contentType=application/json 的
		me.setResolveJsonRequest(JBoltConfig.RESOLVE_JSON_REQUEST_ENABLE);
		//配置cos上传相关
		configCos();
		// 二开项目常量配置
		configConstants(me);
		//调用扩展配置自定义模块列表
		configExtendOfModules();
	}
	/**
	 * 配置项目二开 systemLog日志相关处理器
	 * @return
	 */
	protected abstract JBoltProjectSystemLogProcessor getProjectSystemLogProcessor();
	/**
	 * 配置cos相关
	 */
	protected abstract void configCos();

	/**
	 * 項目常量配置
	 *
	 * @param me
	 */
	public abstract void configConstants(Constants me);

	/**
	 * 項目路由配置
	 *
	 * @param me
	 */
	public abstract void configRoutes(Routes me);

	/**
	 * 項目模板配置
	 *
	 * @param me
	 */
	public abstract void configEngines(Engine me);

	/**
	 * 項目Plugins配置
	 *
	 * @param me
	 */
	public abstract void configPlugins(Plugins me);

	/**
	 * 項目拦截器配置
	 *
	 * @param me
	 */
	public abstract void configInterceptors(Interceptors me);

	@Override
	public void configRoute(Routes me) {
		// 二开专用扩展路由配置
		configRoutes(me);
	}

	@Override
	public void configEngine(Engine me) {
		if(!JBoltConfig.JBOLT_CODE_GEN_ENABLE){
			return;
		}
		me.setToClassPathSourceFactory();
		me.setBaseTemplatePath("/static/");
		// 这里只有选择JFinal TPL的时候才用
		me.setDevMode(JBoltConfig.prop.getBoolean("engine_dev_mode", false));
		me.setCompressorOn();
//		me.setStaticFieldExpression(true);
//		me.setStaticMethodExpression(true);
		// 配置自定义指令
		me.addDirective("ajaxPortal", AjaxPortalDirective.class);
		me.addDirective("realImage", RealImageDirective.class);
		me.addDirective("realUrl", RealUrlDirective.class);
		me.addDirective("datetime", DateTimeDirective.class);
		me.addDirective("prettytime", PrettyTimeDirective.class);
		me.addDirective("permission", PermissionDirective.class);
		me.addDirective("role", RoleDirective.class);
		me.addDirective("rolesn", RoleSnDirective.class);
		me.addDirective("globalConfig", GlobalConfigDirective.class);
		me.addDirective("sex", SexDirective.class);
		me.addDirective("year", YearDirective.class);
		me.addDirective("fileSizeFormatter", FileSizeFormatterDirective.class);
		me.addDirective("rownum", RowNumberDirective.class);
		me.addDirective("action", ActionDirective.class);
		me.addDirective("json", JsonDirective.class);
		me.addDirective("enumToOptions", EnumToOptionsDirective.class);
		me.addDirective("boolToStr", BooleanToStrDirective.class);
		me.addDirective("enable", EnableDirective.class);
		me.addSharedObject("JBoltRequestType", new JBoltRequestType());
		me.addEnum(JBoltUserOnlineState.class);

		// 配置共享对象
		me.addSharedObject("DateUtil", new JBoltDateUtil());
		// 添加CACHE访问
		me.addSharedObject("JBoltUserCache", JBoltUserCache.me);
		me.addSharedObject("JBoltUserConfigCache", JBoltUserConfigCache.me);
		me.addSharedObject("JBoltGlobalConfigCache", JBoltGlobalConfigCache.me);
		me.addSharedObject("JBoltDictionaryCache", JBoltDictionaryCache.me);
		me.addSharedObject("JBoltPermissionCache", JBoltPermissionCache.me);
		me.addSharedObject("JBoltTopnavCache", JBoltTopnavCache.me);
		me.addSharedObject("JBoltRoleCache", JBoltRoleCache.me);
		// 添加角色、权限 静态方法
		me.addSharedStaticMethod(JBoltUserAuthKit.class);
		// 添加GlobalConfig的访问
		me.addSharedObject("GlobalConfigKey", new JBoltGlobalConfigKey());
		// 添加RandomUtil的访问
		me.addSharedObject("RandomUtil", new JBoltRandomUtil());
		// 添加ColorUtil的访问
		me.addSharedObject("ColorUtil", new JBoltColorUtil());
		// 在模板里用枚举工具类
		me.addSharedObject("JBoltEnum", new JBoltEnum());
		// Str字符串工具类
		me.addSharedMethod(new StrKit());
		// 二开扩展配置 模板引擎
		configEngines(me);
	}

	@Override
	public void configPlugin(Plugins me) {
		JBoltConfig.plugins = me;
		//处理配置缓存
		switch (JBoltConfig.JBOLT_CACHE_TYPE) {
			//case JBoltCacheType.EHCACHE:
			//	// 配置Ehcache缓存
			//	me.add(new EhCachePlugin());
			//	break;
			case JBoltCacheType.CAFFEINE:
				JBoltConfig.configCaffeine(me);
				break;
			case JBoltCacheType.REDIS:
				JBoltConfig.configRedis(me);
				break;
		}
		//处理saas 核心分表
		configSaasSeparateTableModels();
		// 配置数据库连接池等插件信息
		configJBoltMainDbPlugin(me);
		// 配置扩展数据源
		JBoltExtendDatabaseConfig.me().config(me,this);
		// 配置事务
		configTx();
		//调用项目自己扩展
		configPlugins(me);
	}

	/**
	 * 配置事务相关
	 */
	private void configTx() {
		//自定义txFun
		Tx.setTxFun((inv,conn)->{
			inv.invoke();
			if(JBoltTxKit.isNeedRollback()){
				String errorMsg = JBoltTxKit.getErrorMsg();
				JBoltTxKit.clear();
				if(StrKit.notBlank(errorMsg)){
					throw new RuntimeException(errorMsg);
				}else{
					throw new RuntimeException("服务发生异常");
				}
			}
		});

	}

	@SuppressWarnings("unchecked")
	private void configSaasSeparateTableModels() {
		if (!JBoltConfig.SAAS_ENABLE) {return;}
		//把内置可以分表给租户的加入
		JBoltModelConfig.me.addInnerSeparateModels(
				User.class,
				Role.class,
				Permission.class,
				RolePermission.class,
				Dept.class,
				Post.class,
				GlobalConfig.class,
				GlobalConfigType.class,
				UserConfig.class,
				OnlineUser.class,
				LoginLog.class,
				RemoteLoginLog.class,
				SystemLog.class,
				Topnav.class,
				TopnavMenu.class
				);

		//添加saas配置的加入分表序列的models packages配置
		JBoltModelConfig.me.addProjectSeparateModelFromSaasConfigPackages(JBoltConfig.prop.get("separate_model_package"));
		//调用项目自定义 租户分表models
		configProjectSaasSeparateTableModels();
	}
	/**
	 * 项目自定义 租户分表models
	 */
	protected abstract void configProjectSaasSeparateTableModels();

	@Override
	public void configInterceptor(Interceptors me) {
		me.addGlobalActionInterceptor(new JBoltExceptionGlobalInterceptor());
		configInterceptors(me);
	}

	@Override
	public void configHandler(Handlers me) {
		JBoltBaseHandler baseHandler = new JBoltBaseHandler();
		// 配置baseHandler 处理页面basePath pmkey 静态资源html直接访问拦截等
		baseHandler.unlimited("/assets/plugins/", "/admin/druid/monitor/");
		//saas处理
		configSaasHandler(me,baseHandler);
		me.add(baseHandler);
		// 配置druid监控 和 druid权限控制
		configDruidMonitor(me);

		// 配置xss攻击 处理器
		me.add(new XssHandler());
		// 根据开关控制websocket
		if (JBoltConfig.JBOLT_WEBSOCKET_ENABLE) {
			configWebsocketHandler(me);
			// me.add(new UrlSkipHandler("^/websocket.ws", false));
		}
		// 二开配置扩展全局处理器
		configHandlers(me, baseHandler);

		if (JBoltConfig.JBOLT_SENTINEL_ENABLE) {
			// 配置自定义UrlBlock处理
			configSentinel();
		}
	}
	private void configSaasHandler(Handlers me,JBoltBaseHandler baseHandler) {
		// 根据开关控制saas
		if (JBoltConfig.SAAS_ENABLE) {
			switch (JBoltConfig.SAAS_TENANT_SN_PARSER) {
				case JBoltSaasTenantSnParser.TYPE_DEFAULT:
					baseHandler.setTenantSnParser(new JBoltSaasTenantSnDefaultParser(JBoltConfig.SAAS_TENANT_SN_KEY));
					break;
				case JBoltSaasTenantSnParser.TYPE_DOMAIN:
					baseHandler.setTenantSnParser(new JBoltSaasTenantSnDomainParser());
					break;
				case JBoltSaasTenantSnParser.TYPE_HEADER:
					baseHandler.setTenantSnParser(new JBoltSaasTenantSnHeaderParser(JBoltConfig.SAAS_TENANT_SN_KEY));
					break;
				default:
					baseHandler.setTenantSnParser(new JBoltSaasTenantSnDomainParser());
					break;
			}
			//设置sn转id实现
			JBoltSaasTenantKit.me.setSnToIdProcessor(getSaasTenantSnToIdProcessor());
			//设置sn转name实现
			JBoltSaasTenantKit.me.setSnToNameProcessor(getSaasTenantSnToNameProcessor());
			//设置id转name实现
			JBoltSaasTenantKit.me.setIdToNameProcessor(getSaasTenantIdToNameProcessor());
			//设置id转sn实现
			JBoltSaasTenantKit.me.setIdToSnProcessor(getSaasTenantIdToSnProcessor());
			//设置Accessible实现
			JBoltSaasTenantKit.me.setAccessibleProcessor(getSaasTenantAccessibleProcessor());
			//设置得到全部租户列表的处理器
			JBoltSaasTenantKit.me.setGetAllTenantsProcessor(getSaasTenantAllDatasProcessor());
			//调用二开
			configSaas(me,baseHandler);
		}
	}

	/**
	 * 获取自定义租户sn转id的实现
	 * @return
	 */
	protected abstract JBoltSaasTenantSnToIdProcessor getSaasTenantSnToIdProcessor();
	/**
	 * 获取自定义租户sn转name的实现
	 * @return
	 */
	protected abstract JBoltSaasTenantSnToNameProcessor getSaasTenantSnToNameProcessor();
	/**
	 * 获取自定义租户id转name的实现
	 * @return
	 */
	protected abstract JBoltSaasTenantIdToNameProcessor getSaasTenantIdToNameProcessor();
	/**
	 * 获取自定义租户id转sn的实现
	 * @return
	 */
	protected abstract JBoltSaasTenantIdToSnProcessor getSaasTenantIdToSnProcessor();
	/**
	 * 获取自定义租户是否可访问 Accessible的实现
	 * @return
	 */
	protected abstract JBoltSaasTenantAccessibleProcessor getSaasTenantAccessibleProcessor();

	/**
	 * 获取所有租户列表的处理器
	 * @return
	 */
	protected abstract JBoltSaasTenantGetAllProcessor getSaasTenantAllDatasProcessor();

	/**
	 * 获取扩展模块列表使用的enmu的className
	 * @return
	 */
	protected abstract String getExtendOfModuleEnumClassSimpleName();

	/**
	 * 自定义扩展模块的列表
	 * @return
	 */
	protected void configExtendOfModules(){
		JBoltConfig.EXTEND_OF_MODULES = getExtendOfModules();
		JBoltConfig.EXTEND_OF_MODULE_ENUM_CLASS_SIMPLE_NAME = getExtendOfModuleEnumClassSimpleName();
	}

	/**
	 * 自定义扩展模块的列表
	 * @return
	 */
	protected abstract List<JBoltEnumBean> getExtendOfModules();

	/**
	 * saas模式扩展
	 * @param me
	 * @param baseHandler
	 */
	protected abstract void configSaas(Handlers me, JBoltBaseHandler baseHandler);

	/**
	 * 配置Sentinel
	 */
	protected abstract void configSentinel();

	/**
	 * 配置handler
	 *
	 * @param me
	 * @param baseHandler
	 */
	protected abstract void configHandlers(Handlers me, JBoltBaseHandler baseHandler);

	/**
	 * 配置websocket
	 *
	 * @param me
	 */
	protected abstract void configWebsocketHandler(Handlers me);

	/**
	 * 配置druid监控
	 *
	 * @param me
	 */
	protected abstract void configDruidMonitor(Handlers me);

	/**
	 * 创建一个Druid配置插件
	 *
	 * @return
	 */
	public static DruidPlugin createDruidPlugin() {
		JBoltConfig.loadConfig();
		String user = JBoltConfig.prop.get("user");
		String password = JBoltConfig.prop.get("password");
		boolean is_encrypted = JBoltConfig.prop.getBoolean("is_encrypted",false);
		if(is_encrypted){
			user = JBoltDesUtil.getDecryptData(user);
			password = JBoltDesUtil.getDecryptData(password);
		}
		DruidPlugin druidPlugin = new DruidPlugin(JBoltConfig.prop.get("jdbc_url"), user,password);
		if(!DBType.isDM(JBoltConfig.MAIN_DB_TYPE)){
			// 配置防火墙
			WallFilter wallFilter = new WallFilter(); // 加强数据库安全
			wallFilter.setDbType(JBoltConfig.MAIN_DB_TYPE);
			if (JBoltConfig.isOracle()) {
				// oracle关闭FunctionCheck
				WallConfig wallConfig = wallFilter.getConfig();
				if (wallConfig == null) {
					wallConfig = new WallConfig();
					wallFilter.setConfig(wallConfig);
				}
				wallConfig.setFunctionCheck(false);
			}
			druidPlugin.addFilter(wallFilter);
		}
		// 统计监控的过滤器
		StatFilter statFilter = new StatFilter();
		statFilter.setMergeSql(true);
		statFilter.setLogSlowSql(true);
		statFilter.setDbType(JBoltConfig.MAIN_DB_TYPE);
		statFilter.setSlowSqlMillis(Duration.ofMillis(1000).toMillis());
		// 添加 StatFilter 才会有统计数据
		druidPlugin.addFilter(statFilter);

		if (JBoltConfig.DEV_MODE && JBoltConfig.JBOLT_DRUID_DEV_MODE_FULL_SQL_LOG){
			// 2.日志插件
			// 保存DruidDataSource的监控记录,设置打印日志周期,默认使用DruidDataSourceStatLoggerImpl
			druidPlugin.setTimeBetweenLogStatsMillis(24 * 60 * 60 * 1000);
//			druidPlugin.setConnectionProperties("druid.timeBetweenLogStatsMillis=" + Duration.ofHours(24).toMillis());
			Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
			slf4jLogFilter.setConnectionLogEnabled(false);
			slf4jLogFilter.setResultSetLogEnabled(false);
			slf4jLogFilter.setStatementParameterSetLogEnabled(false);
			slf4jLogFilter.setConnectionLogEnabled(false);
			slf4jLogFilter.setResultSetCloseAfterLogEnabled(false);
			slf4jLogFilter.setConnectionCloseAfterLogEnabled(false);
			slf4jLogFilter.setStatementParameterClearLogEnable(false);
			slf4jLogFilter.setStatementPrepareAfterLogEnabled(false);
			slf4jLogFilter.setStatementPrepareCallAfterLogEnabled(false);
			slf4jLogFilter.setStatementCreateAfterLogEnabled(false);
			slf4jLogFilter.setStatementCloseAfterLogEnabled(false);

			// 设置输出执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteAfterLogEnabled(false);
			// 设置批量操作执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteBatchAfterLogEnabled(false);
			// 设置查询操作执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteQueryAfterLogEnabled(false);
			// 设置更新 插入 删除 操作执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteUpdateAfterLogEnabled(false);
			// 输出完整的SQL 将值替换掉问号，这个仅在开发模式下有效
			slf4jLogFilter.setStatementExecutableSqlLogEnable(true);

			druidPlugin.addFilter(slf4jLogFilter);
		}
		if (JBoltConfig.MAIN_DB_TYPE.equals(DBType.MYSQL)) {
			// 指定初始化 编码为utf8mb4
			druidPlugin.setConnectionInitSql("set names utf8mb4");
		}
		return druidPlugin;
	}

	/**
	 * 配置数据库连接池等插件信息
	 *
	 * @param me
	 */
	private void configJBoltMainDbPlugin(Plugins me) {
		// 配置数据库连接池插件
		DruidPlugin dbPlugin = createDruidPlugin();
		me.add(dbPlugin);
		// orm映射 配置ActiveRecord插件
		JBoltActiveRecordPlugin arp = new JBoltActiveRecordPlugin(dbPlugin);
		switch (JBoltConfig.JBOLT_CACHE_TYPE) {
		case JBoltCacheType.CAFFEINE:
			arp.setCache(new CaffeineCache());
			break;
		case JBoltCacheType.REDIS:
			arp.setCache(new RedisCache());
			break;
		}
		arp.addAutoBindPackage(JBoltConfig.prop.get("model_package"));
		me.add(arp);
		// 设置方言
		JBoltConfig.setDialect(arp);
		// 设置加载位置
		Engine sqlEngine = arp.getEngine();
		// 配置模板热加载
		sqlEngine.setDevMode(JBoltConfig.prop.getBoolean("dbsql_engine_dev_mode", false));
		sqlEngine.setSourceFactory(new ClassPathSourceFactory());
//		sqlEngine.setStaticFieldExpression(true);
//		sqlEngine.setStaticMethodExpression(true);
		sqlEngine.setCompressorOn(' ');
		sqlEngine.addDirective("sqlValue", SqlValueDirective.class);
		sqlEngine.addDirective("likeValue", LikeValueDirective.class);
		sqlEngine.addSharedObject("SqlUtil", new SqlUtil());
		// 设置不区分大小写
		arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));
		// 配置加载Sql模板的具体路径
		arp.addSqlTemplate("/sql/" + JBoltConfig.MAIN_DB_TYPE + "/all_sqls.sql");
		// 处理二开配置扩展
		configMainDbPlugins(dbPlugin, arp, sqlEngine);
	}

	@Override
	public void onStart() {
		//初始化内置应用
		Application application = JBoltApplicationCache.me.getInnerPlatformApplication();
		if(application == null){
			throw new RuntimeException("平台首次初始化获取内置应用Application失败");
		}
		//初始化JBoltDataSource
		JBoltDataSourceUtil.me.init();
		//如果开启了敏感词词库
		if(JBoltConfig.SENSITIVE_WORD_CHECK_ENABLE){
			//初始化敏感词词库
			JBoltSensitiveWordUtil.me.init();
		}
		//初始化Jwt检测因子配置
		initJwtCheckToken();
		//如果开启了redis
		if(JBoltCacheType.REDIS.equals(JBoltConfig.JBOLT_CACHE_TYPE)) {
			//初始化redis lua脚本 sha
			JBoltRedisRateLimitUtil.initRedisLuaScriptSha();
		}


		initDataSourceTableMetas();

	}


	/**
	 * 开发模式下，项目启动1s后，完成table metas的构建
	 */
	private void initDataSourceTableMetas() {
		if (JBoltConfig.pdevIsPro() == false) {
			new Thread(() -> {
                try {
                    Thread.sleep(1000);
					List<JBoltDatasource> allDatasource = JBoltDataSourceUtil.me.getAllDatasource();
					allDatasource.forEach(item -> {
						JBoltDataSourceUtil.me.initJBoltDatasourceTables(item);
					});
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();
		}
	}

	/**
	 * 初始化Jwt检测因子配置
	 */
	public static void initJwtCheckToken() {
		//是否检测JWT API USER有效性
		JBoltConfig.IS_NEED_CHECK_JWT_API_USER_EFFECTIVE = JBoltGlobalConfigCache.me.getCheckJwtApiUserEffectiveEnable();
		//检测JWT API USER 有效性专用token
		JBoltConfig.CHECK_JWT_API_USER_EFFECTIVE_TOKEN = JBoltGlobalConfigCache.me.getCheckJwtApiUserEffectiveToken();
	}

	@Override
	public void onStop() {

	}

	/**
	 * 主数据源的插件配置扩展
	 *
	 * @param dbPlugin
	 * @param arp
	 * @param sqlEngine
	 */
	protected abstract void configMainDbPlugins(DruidPlugin dbPlugin, JBoltActiveRecordPlugin arp, Engine sqlEngine);

	/**
	 * 扩展数据源的插件配置扩展
	 * @param dbPlugin
	 * @param arp
	 * @param sqlEngine
	 * @param configName
	 * @param dbSetting
	 */
	protected abstract void configExtendDbPlugins(DruidPlugin dbPlugin, JBoltActiveRecordPlugin arp, Engine sqlEngine, String configName, Setting dbSetting);
}
